Wiki

Clone wiki

Data Bind / Advanced / Create Your Own Formatter

Sometimes, you want to format your data in a specific way before presenting it to the user. A common use case is showing a timer: In your data model, the remaining time would most probably be represented by some floating point value, such as 72.6 seconds. Now, you'd like to show a timer that should read "1:12" instead. For all we know, we'd be forced to introduce an additional string property in our data context, which is updated every time the timer field is changed. As this is tedious at best, Data Bind allows you to create your own formatters for modifying data before it is consumed by our UI (such as your TextTextSetter).

For sake of simplicity, let's say we want to create a formatter that converts a given string to all upper-case, for showing the player name in a high-score list, for instance. For this, we're going to need four things:

  • a new class extending DataProvider,
  • an input value to format,
  • a conversion method for formatting the input value, and
  • a notification whenever the input value changes

The DataProvider class provides a nice abstraction for the UI to get their data from. Remember that your UI can get its data from basically any source through bindings. You already know the most important data binding: The one that gets data from a context and passes it to the UI. DataProviders are just another type of source to feed your UI from.

Let's take a look at our StringToUpperFormatter in detail:

#!c#

namespace Slash.Unity.DataBind.Examples.StringToUpperFormatter
{
    using Slash.Unity.DataBind.Core.Presentation;

    /// <summary>
    ///   Formatter for converting strings to upper-case.
    /// </summary>
    public class StringToUpperFormatter : DataProvider
    {
        #region Fields

        /// <summary>
        ///   Data value to convert to upper-case.
        /// </summary>
        public DataBinding Argument;

        #endregion

        #region Public Properties

        public override object Value
        {
            get
            {
                // Get data to convert.
                var argument = this.Argument.GetValue<string>();

                // Convert to upper-case.                               
                return string.IsNullOrEmpty(argument) ? string.Empty : argument.ToUpper();
            }
        }

        #endregion

        #region Methods

        /// <summary>
        ///   Unity callback.
        /// </summary>
        protected void Awake()
        {
            // Add bindings.
            this.AddBinding(this.Argument);
        }

        protected override void UpdateValue()
        {
            // Convert value and notify interested listeners.
            this.OnValueChanged(this.Value);
        }

        #endregion
    }
}

The argument for our formatter is provided by an arbitrary DataBinding again. This means that the value can come either from a context - or from another formatter! Huh.

Conversion of the argument is done in the getter of the Value property. Finally, we need to know whenever our input value changes, and notify listeners of the converted values in turn. This is done by calling the AddBinding method and OnValueChanged method, respectively.

Note that you can format values by an arbitrary chain of formatters, passing values to each other, before finally handing it over to the UI. This is where the idea of data bindings becomes really powerful!

Time to put our formatter into action! Create a UI with the framework of your choice (i.e. Unity UI or NGUI). Now, before passing your data value from your context from the UI, use your new StringToUpperFormatter by specifying it as the data provider of your setter. In Unity UI, this could look like this:

12058649.png

The StringToUpperFormatter example scenes illustrate the usage of the formatter by showing an input text field whose value is converted to upper-case and shown in another label.

Clearly, you could change your data in any way you want before passing it on. You can combine multiple values into a single one, and even change their types: The Slash.Unity.DataBind.Foundation.Checks.EqualityCheck, for instance, takes two arguments of any type and returns a boolean value indicating whether both arguments are equal, or not. EqualityCheck extends the DataProvider class, just as our little StringToUpperFormatter does.

Once written, these data providers can be used over and over again, without having to duplicate or change any existing code. Time to roll your own!

Updated